//--------------------------------------------------------------------------------------
// Constant Buffer Variables
//--------------------------------------------------------------------------------------
texture torus_texture;

float4x4 world;
float4x4 view;
float4x4 projection;
float4x4 normal_matrix;
float wave_offset;

// lighting variables
float3 light_dir;
float material_specular_power;
float4 light_color;
float4 ambient_material_color;
float4 diffuse_material_color;
float4 specular_material_color;    

//--------------------------------------------------------------------------------------
// Texture samplers
//--------------------------------------------------------------------------------------
sampler torus_texture_sampler = 
sampler_state
{
    Texture = <torus_texture>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    AddressU = MIRROR;
    AddressV = MIRROR;
    AddressW = MIRROR;
};

//--------------------------------------------------------------------------------------
struct VS_INPUT
{
    float3 Pos : POSITION;
    float3 Norm : NORMAL;
    float2 Tex : TEXCOORD;
};

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float4 Color : COLOR0;
    float2 Tex : TEXCOORD;        
};

//--------------------------------------------------------------------------------------
// Helper Functions
//--------------------------------------------------------------------------------------
struct ColorOut
{
    float4 ambient;
    float4 diffuse;
    float4 specular;
};

ColorOut DirectionalLight(float3 normal, float3 view_dir)
{
    // math done in view coordinates
    float3 light_dir_vc = -normalize( mul(light_dir, (float3x3)view) ); // there is no scale in view matrix
    
    float3 double_normal = 2.0f * normal;
    float doublenDotL = dot(double_normal, light_dir_vc);
    float3 reflexion = doublenDotL * normal - light_dir_vc;
    float vDotR = max(0.0, dot(view_dir, reflexion));

    float nDotL = max(0.0, dot(normal, normalize(light_dir_vc)));
        
    ColorOut output;
    output.ambient = light_color;
    output.diffuse = light_color * nDotL;
    output.specular = light_color * pow(vDotR, material_specular_power);
    
    return output;
}


//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;

    float beta = input.Tex.x * 2.0f * 3.14159f;
    input.Pos = input.Pos + sin( 4.0f * (wave_offset.x + beta)) * input.Norm * 0.05f;

    float4 worldspace_position = mul( float4(input.Pos,1.0f), world );
    float4 viewspace_position = mul( worldspace_position, view );
    output.Pos = mul( viewspace_position, projection );

    float3 viewspace_normal = normalize(mul(input.Norm, (float3x3)normal_matrix));
    
    float4 viewspace_view_dir = -normalize(viewspace_position);

    ColorOut directional_color = DirectionalLight(viewspace_normal, viewspace_view_dir);
    output.Color = saturate(ambient_material_color * directional_color.ambient + diffuse_material_color * directional_color.diffuse + specular_material_color * directional_color.specular);
    
    output.Tex = input.Tex;
        
    return output;
}


//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( PS_INPUT input) : SV_Target
{
    float alpha = input.Tex.y * 2.0f * 3.14159f;
    input.Tex.x = input.Tex.x + sin( 2.0f*(alpha + wave_offset.x) );
    return tex2D( torus_texture_sampler, input.Tex * 8.0f) * input.Color;
}

technique RenderTechnique
{
    pass P0
    {          
        VertexShader = compile vs_3_0 VS();
        PixelShader  = compile ps_3_0 PS();
    }
}
